﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Windows.Graphics.Effects;
using Windows.UI.Composition;
using Windows.Foundation;
using Yinyue200.Sharp2D.Interop;
using Windows.Foundation.Collections;
using PackageTuple;

namespace Yinyue200.Sharp2D.Direct2D.Effects
{
    public abstract class Effect : Interop.IGraphicsEffectD2D1Interop, IGraphicsEffect, IGraphicsEffectSource,IDisposable
    {

        public static CppWrapper.PropertyValueOwner PropertyValueOwner { get; set; } = new CppWrapper.PropertyValueOwner();
        public Effect()
        {
            pes.Add(null);
        }
        public abstract void GetEffectId(out Guid id);
        public IntPtr Convert(long ptr)
        {
            var intptr = new IntPtr(ptr);
            Guid guid = SharpDX.Utilities.GetGuidFromType(typeof(IPropertyValue));
            Marshal.QueryInterface(intptr, ref guid, out var ppv);
            return intptr;
            //return System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(intptr);
        }

        //public Dictionary<string, WriteableTuple<uint, GRAPHICS_EFFECT_PROPERTY_MAPPING>> mapping { get; set; } = new Dictionary<string, WriteableTuple<uint, GRAPHICS_EFFECT_PROPERTY_MAPPING>>();
        public void GetNamedPropertyMapping([MarshalAs(UnmanagedType.LPWStr)] string name, out uint index, out GRAPHICS_EFFECT_PROPERTY_MAPPING mapping)
        {
            var vl = this.map2[name];
            index = (uint)(vl.Item1);
            mapping = vl.Item2;
        }

        public void GetPropertyCount(out uint count)
        {
            count = (uint)objs.Count;
        }

        public void GetPropertyInner(uint index, out object value)
        {
            value = objs[(int)index];
        }

        public object GetProperty(string name)
        {
            return Marshal.GetObjectForIUnknown(objs[map2[name].Item1]);
        }

        protected List<IGraphicsEffectSource> pes { get; set; } = new List<IGraphicsEffectSource>();


        public void GetSource(uint index, out IGraphicsEffectSource source)
        {
            source = pes[(int)index];
        }

        public void GetSourceCount(out uint count)
        {
            count = (uint)pes.Count;
        }
        protected Dictionary<string, WriteableTuple<int, GRAPHICS_EFFECT_PROPERTY_MAPPING>> map2 = new Dictionary<string, WriteableTuple<int, GRAPHICS_EFFECT_PROPERTY_MAPPING>>();
        protected List<IntPtr> objs = new List<IntPtr>();
        public Windows.Graphics.Effects.IGraphicsEffectSource Source
        {
            get
            {
                GetSource(0, out var source);
                return source;
            }
            set
            {
                pes[0] = value;
            }
        }

        protected void SetBoxedProperty(string name,IntPtr value, Interop.GRAPHICS_EFFECT_PROPERTY_MAPPING em = Interop.GRAPHICS_EFFECT_PROPERTY_MAPPING.GRAPHICS_EFFECT_PROPERTY_MAPPING_DIRECT)
        {
            map2.Add(name,new WriteableTuple<int, Interop.GRAPHICS_EFFECT_PROPERTY_MAPPING>(objs.Count, em));
            objs.Add(value);
        }

        public void SetProperty(string name,IntPtr value, Interop.GRAPHICS_EFFECT_PROPERTY_MAPPING? em = null)
        {
            if (map2.TryGetValue(name, out var value1))
            {
                objs[value1.Item1] = value;
                if (em.HasValue)
                {
                    value1.Item2= em.Value;
                }
            }
            else if (em.HasValue)
            {
                SetBoxedProperty(name, value, em.Value);
            }
            else
            {
                throw new ArgumentNullException(nameof(em));
            }
        }

        public virtual string Name { get; set; }

        public void GetProperty(uint index, out IntPtr value)
        {
            GetPropertyInner(index, out object value1);
            //System.Buffer.MemoryCopy(value1)
            value = (IntPtr)value1;
            Marshal.AddRef(value);
        }

        #region IDisposable Support
        private bool disposedValue = false; // 要检测冗余调用

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // TODO: 释放托管状态(托管对象)。
                }

                // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                // TODO: 将大型字段设置为 null。
                foreach(var one in objs)
                {
                    while (Marshal.Release(one) > 0) ;
                }
                objs.Clear();

                disposedValue = true;
            }
        }

        // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
        ~Effect()
        {
            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            Dispose(false);
        }

        // 添加此代码以正确实现可处置模式。
        public void Dispose()
        {
            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            Dispose(true);
            // TODO: 如果在以上内容中替代了终结器，则取消注释以下行。
            GC.SuppressFinalize(this);
        }
        #endregion
        //class nullablepk
        //{
        //    public IntPtr intptr;
        //    public object content;
        //}
        //private nullablepk ConvertObjectToIPropertyValue<T>(T value) where T : struct
        //{
        //    T? nu = value;
        //    //var guid = Guid.Parse("61c17706-2d65-11e0-9ae8-d48564015472");//interface IReference<T> : IPropertyValue
        //    //System.Runtime.InteropServices.Marshal.QueryInterface(, ref guid, out IntPtr pi);
        //    //return (IPropertyValue)Marshal.GetObjectForIUnknown(pi);
        //    return new nullablepk() { intptr = Marshal.GetIUnknownForObject(nu), content = nu };
        //}
        //[ComImport]
        //[Guid("61c17706-2d65-11e0-9ae8-d48564015472")]
        //// Note that ideally, T should be constrained to be a value type.  However, Windows uses IReference<HSTRING>
        //// and the projection may not be exactly pretty.
        //internal interface IReference<T> : IPropertyValue
        //{
        //    T Value { get; }
        //}

        //[ComImport]
        //[Guid("61c17707-2d65-11e0-9ae8-d48564015472")]
        //// T can be any WinRT-compatible type, including reference types.
        //internal interface IReferenceArray<T> : IPropertyValue
        //{
        //    T[] Value { get; }
        //}
        //public void GetProperty(uint index, out IntPtr value)
        //{
        //    GetProperty(index, out object value1);
        //    var guid = Guid.Parse("61c17706-2d65-11e0-9ae8-d48564015472");//interface IReference<T> : IPropertyValue
        //    System.Runtime.InteropServices.Marshal.QueryInterface(Marshal.GetIUnknownForObject(value1), ref guid, out IntPtr pi);
        //    value = pi;
        //}
    }
}

